#!/usr/bin/env php

<?php

class vuePoem {

    private $argv;
    private string $help_info = <<<EOF
\nvuePoem cli help (vuePoem [option])
--------------------------------------
check  :Checking the Operating Environment
dev    :Automatic loading of Vue and PHP development servers
build  :Vue projects are packaged as static resources in /server/public/
docker :Start with docker
clean  :Clean up build front-end resources
mysql  :Automatic Database deployment\n\n
EOF;
    private string $check_template = <<<EOF
path  : {status_path}
php   : {status_php}
node  : {status_node}
npm   : {status_npm}
mysql : {status_mysql}\n\n
EOF;
    private $env;
    private array $env_required_fields = [
        'MYSQL_HOST', 'MYSQL_PORT', 'MYSQL_USER', 'MYSQL_PASS', 'MYSQL_DBNM', 'MYSQL_PREFIX', 'MYSQL_CHARSET',
        'VUE_HOST', 'VUE_PORT', 'VUE_PROJECT_PATH',
        'PHP_HOST', 'PHP_PORT'
    ];
    private $docker_env;

    public function __construct() {

        date_default_timezone_set('PRC');

        if(PHP_SAPI != 'cli') {
            $this->log('only support cli request');
            exit;
        }

        $this->argv = $_SERVER['argv'];
        if(empty($this->argv) || empty($this->argv[1]) || $this->argv[1] == 'help' || $this->argv[1] == 'run') {
            echo $this->help_info;
            exit;
        }else {
            unset($this->help);
        }

        $this->load_env();
    }

    public function run() {

        $argv = strtolower($this->argv[1]);
        $this->$argv();
    }

    private function dev() {

        $php_path = realpath($this->env['PHP_PROJECT_PATH']);
        $vue_path = realpath($this->env['VUE_PROJECT_PATH']);

        if(!file_exists($vue_path . '/node_modules')) {
            $this->log("cd {$this->env['VUE_PROJECT_PATH']}/ && npm i", true);
            exit;
        }

        $this->log(__FUNCTION__ . ' running...');
        $this->log('press ctrl+c to quit');
        $this->log("cd {$php_path}/public/ && php -S {$this->env['PHP_HOST']}:{$this->env['PHP_PORT']} index.php & cd {$vue_path} && npm run dev", true);
    }

    private function build() {

        $this->log(__FUNCTION__ . ' running...');
        $this->log("cd {$this->env['VUE_PROJECT_PATH']} && npm run build", true);
        $this->log(__FUNCTION__ . ' finished');
    }

    private function docker() {

        $this->log(__FUNCTION__ . ' running...');
        $this->log('press ctrl+c to quit');
        $this->log('docker -v && node -v && npm -v', true);

        $this->build();

        $this->log("cd {$this->env['DOCKER_PATH']} && docker-compose up -d", true);

        sleep(2);
        $this->mysql(__FUNCTION__);

        $this->log("cd {$this->env['DOCKER_PATH']} && docker-compose down", true);

        sleep(2);
        switch (PHP_OS) {
            case 'Linux': {
                $this->log("xdg-open http://127.0.0.1:{$this->docker_env['NGINX_HTTP_HOST_PORT']}", true);
                break;
            }
            case 'Darwin': {
                $this->log("open http://127.0.0.1:{$this->docker_env['NGINX_HTTP_HOST_PORT']}", true);
                break;
            }
        }

        $this->log("cd {$this->env['DOCKER_PATH']} && docker-compose up", true);
    }

    private function clean() {

		$www_root_dir = scandir($this->env['PHP_PROJECT_PATH'].'/public');

		foreach ($www_root_dir as $item) {
			if(in_array($item, ['.', '..', 'index.php'])) {
				continue;
			}
            $this->log("rm -rf {$this->env['PHP_PROJECT_PATH']}/public/{$item}", true);
		}
        $this->log('clean success');
    }

    private function mysql($from = '') {

        $tables = file_get_contents('vuePoem.sql');
        $tables = str_replace('{PREFIX}', $this->env['MYSQL_PREFIX'], $tables);
        $tables = str_replace('{CHARSET}', $this->env['MYSQL_CHARSET'], $tables);

        try {

            if($from == 'docker') {

                $this->docker_env = parse_ini_file('./docker/.env');
                $has_db = 0;
                $mysql = new PDO("mysql:host=127.0.0.1;port={$this->docker_env['MYSQL_HOST_PORT']}", $this->env['MYSQL_USER'], $this->docker_env['MYSQL_ROOT_PASSWORD']);
                $mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                $re = $mysql->query('show databases;')->fetchAll(PDO::FETCH_ASSOC);
                foreach ($re as $item) {
                    if($item['Database'] == $this->env['MYSQL_DBNM']) {
                        $has_db++; break;
                    }
                }
                if(!$has_db) {
                    $mysql->exec('CREATE DATABASE IF NOT EXISTS ' . $this->env['MYSQL_DBNM']);
                    $mysql->exec('USE ' . $this->env['MYSQL_DBNM']);
                    if(empty($tables)) {
                        $this->log('vuePoem.sql not found');
                        exit;
                    }
                    $mysql->exec($tables);
                    $this->log('mysql db & tables init success');
                }

            }else {

                $mysql = new PDO("mysql:host={$this->env['MYSQL_HOST']}", $this->env['MYSQL_USER'], $this->env['MYSQL_PASS']);
                $mysql->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
                $mysql->exec('CREATE DATABASE IF NOT EXISTS ' . $this->env['MYSQL_DBNM']);
                $mysql->exec('USE ' . $this->env['MYSQL_DBNM']);
                if(empty($tables)) {
                    $this->log('vuePoem.sql not found');
                    exit;
                }
                $mysql->exec($tables);
                $this->log('mysql db & tables init success');
            }

        }catch (PDOException $e) {
            $this->log('auto create database ' . $this->env['MYSQL_DBNM'] . "\n" . $e);
            exit;
        }
    }

    private function check() {

        $status = [];
        $path_check = [
            '.env',
            $this->env['PHP_PROJECT_PATH'].'/public/index.php',
            $this->env['PHP_PROJECT_PATH'].'/phppoem/core',
            $this->env['PHP_PROJECT_PATH'].'/app/admin/controller',
            $this->env['PHP_PROJECT_PATH'].'/app/service/middleware',
            $this->env['VUE_PROJECT_PATH']
        ];

        $status['status_path'] = '';
        foreach ($path_check as $key => $path) {
            if(!file_exists($path)) {
                $status['status_path'] .= "[no:{$path}] ";
            }else {
                $status['status_path'] .= "[ok:{$path}] ";
            }
        }
        exec("php -v", $status['status_php']);
        exec("node -v", $status['status_node']);
        exec("npm -v", $status['status_npm']);
        exec("mysql -V", $status['status_mysql']);

        if(!empty($status['status_php']) && is_array($status['status_php'])) {
            $status['status_php'] = implode(' - ', array_filter($status['status_php']));
        }else {
            $status['status_php'] = 'Environment and global variables need to be checked';
        }
        if(!empty($status['status_node']) && is_array($status['status_node'])) {
            $status['status_node'] = implode(' - ', array_filter($status['status_node']));
        }else {
            $status['status_node'] = 'Environment and global variables need to be checked';
        }
        if(!empty($status['status_npm']) && is_array($status['status_npm'])) {
            $status['status_npm'] = implode(' - ', array_filter($status['status_npm']));
        }else {
            $status['status_npm'] = 'Environment and global variables need to be checked';
        }
        if(!empty($status['status_mysql']) && is_array($status['status_mysql'])) {
            $status['status_mysql'] = implode(' - ', array_filter($status['status_mysql']));
        }else {
            $status['status_mysql'] = 'Environment and global variables need to be checked';
        }

        foreach ($status as $key => $item) {
            $this->check_template = str_replace("{{$key}}", $item, $this->check_template);
        }

        echo $this->check_template;
        exit;
    }

    private function log($info = '', $command = false) {

        if(empty($info)) {
			return false;
        }

        echo 'VuePoem: ' . date('Y-m-d H:i:s') . " - {$info} \n";

        if($command) {
            system($info);
        }
    }

    private function load_env() {

        if(!file_exists('.env')) {
            $this->log('.env file not found');
        }

        $this->env = parse_ini_file('.env', true);

        if($this->env['VUE_PROJECT_PATH']) {
            $this->env['VUE_PROJECT_PATH'] = realpath($this->env['VUE_PROJECT_PATH']);
        }

        $err_flag = 0;
        foreach ($this->env_required_fields as $field) {
            if(!isset($this->env[$field])) {
                $this->log("Check .env file required field: {$field}");
                $err_flag++;
            }
        }
        if($err_flag) {
            exit;
        }
    }

    public function __call($name, $arguments) {
        $this->log($name . ' is not a support option');
    }

    public function __destruct() {
        if(count($this->argv) > 1) {
            if(!in_array($this->argv[1], ['check', 'help']) && !empty($this->argv[1])) {
                $this->log('bye!');
            }
        }
    }
}

(new vuePoem())->run();


